//MComboBoxPopup.java
//重写组合框Popup菜单
package org.vacoor.ui.qq.combobox;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.Map;

import javax.swing.BorderFactory;
import javax.swing.DefaultComboBoxModel;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.plaf.basic.BasicComboPopup;

import org.vacoor.ui.qq.resources.UIResourceManager;


public class QQComboBoxPopup extends BasicComboPopup {
	private static final long serialVersionUID = 1L;
	private QQComboBox MComboBox;
    private Color borderColor;      //列表面板的边框颜色
    private Color backColor;        //未选择的背景色
    private Color foreColor;
    private Color selectBackColor;      //选择项的背景色
    private Color selectNameForeColor;      //选择项姓名的前景色
    private Color selectNumForeColor;       //选择项 号码的前景色
    private Font numFont;           //未选择项num字体
    private Font selectNameFont;        //姓名选择项字体
    private Font selectNumFont;
    private Dimension maxIconDim;       //Popup中图标大小
    private Dimension minIconDim;       //输入框中图标大小
    //Popup菜单中最多选项个数,添加数量超过popupSize则取前popupSize个
    private int popupSize = 9999;
    //创建一个MComboBoxItem到JComponent的映射对,存放所有选择项和其面板的映射
    private Map<QQComItem, JComponent> values;
    private JPanel listPanel;       //弹出菜单列表面板
    private JLabel labelX;          //delete标签

    public QQComboBoxPopup(QQComboBox MComboBox) {
        super(MComboBox);
        this.MComboBox = MComboBox;
        //设置显示最大对象数,超过后将使用滚动条
        //选项不设置缺省大小可以使用,但会导致间隔过大
        MComboBox.setMaximumRowCount(5);
        initCBP();
    }

    private void initCBP() {
        borderColor = new Color(0, 147, 209);
//        backColor = UIManager.getColor("ComboBox.background");
//        foreColor = UIManager.getColor("ComboBox.foreground");
        backColor = Color.WHITE;
        foreColor = Color.BLACK;
        selectBackColor = new Color(55, 143, 207);
        selectNameForeColor = Color.BLACK;
        selectNumForeColor = Color.WHITE;
        numFont = new Font(Font.DIALOG, Font.PLAIN, 11);
        selectNameFont = new Font("微软雅黑", Font.PLAIN, 12);
        selectNumFont = new Font(Font.DIALOG, Font.PLAIN, 11);
        maxIconDim = MComboBox.getMaxIconDim();
        minIconDim = MComboBox.getMinIconDim();
//        labelX = new JLabel(new ImageIcon(getClass().getResource("/ImageLoader/xIcon.png")));
        labelX = new JLabel(UIResourceManager.getMComPopupCloseImg());
        listPanel = new JPanel(new GridBagLayout());
        values = new HashMap<QQComItem, JComponent>();



        //开始添加数据
        values.clear();         //清除所有映射
        DefaultComboBoxModel model = (DefaultComboBoxModel) comboBox.getModel();
        int modelSize = model == null ? 0 : model.getSize();
        int endIndex = modelSize < popupSize ? modelSize : popupSize;
        this.removeAll();
        for (int i = 0; i < endIndex; i++) {
            //返回索引处的Object类型菜单项并转换
            QQComItem item = (QQComItem) model.getElementAt(i);
            JPanel itemPanel = new JPanel();
            setItemPanel(itemPanel, item);
            //将选择项和其面板进行映射
            values.put(item, itemPanel);
            //添加监听
            MyItemListener myItemListener = new MyItemListener(item, itemPanel, labelX);
            itemPanel.addMouseListener(myItemListener);
            itemPanel.addMouseMotionListener(myItemListener);
            //Y方向上添加组件
            listPanel.add(itemPanel, new GridBagConstraints(0, i, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
        }

//       if (modelSize == 0 && isBDefaultIconShow() && getDefaultIcon() != null) {  
//            MComboBoxItem _entry = new MComboBoxItem(  
//                    getDefaultIcon(), "");  
//            _model.insertElementAt(_entry, 0);  
//            _model.setSelectedItem(_entry);  
//        }

        this.setBorder(BorderFactory.createLineBorder(borderColor));
        this.setLayout(new BorderLayout());
//        JScrollPane listSP = new JScrollPane(listPanel);
//        listSP.setBorder(null);
//        //启用/禁用对鼠标滚轮滚动的移动响应。
//        listSP.setWheelScrollingEnabled(true);
//        listSP.setAutoscrolls(true);
//        //设置水平滚动条不显示
//        listSP.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
//        this.add(listSP, "Center");
        this.add(listPanel, "Center");
        //不能设置大小，只能使用pack()否则删除后间隔越来越大
        //this.setPreferredSize(new Dimension(180,this.getPreferredSize().height));
//        this.pack();


    }

    //不同状态选择项面板设置
    //设置项面板未选择状态面板
    public void setItemPanel(JPanel panel, QQComItem item) {
        JPanel itemPanel = panel;

        //调用图片缩放方法创建头像标签
        JLabel labelIcon = new JLabel(getResizePicture((ImageIcon) item.getIcon(), minIconDim));

        JLabel labelNum = new JLabel(item.getNum());     //号码标签

        labelIcon.setBorder(BorderFactory.createEmptyBorder(0, 2, 0, 2));
        labelNum.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));

        labelNum.setFont(numFont);
        labelNum.setForeground(foreColor);
        labelNum.setBackground(backColor);
        itemPanel.setBackground(backColor);

        itemPanel.removeAll();

        itemPanel.setLayout(new GridBagLayout());

        //GridBagLayout用法 下面x,y为x轴 y轴
        //组件 new GridBagConstraints(位置x,y, 组件单元格数x,y, 分布额外空间处理x,y,组件小于区域处理x,y, 组件大于区域x,y, 分配权限, Y, 分给多大x,y)      
        itemPanel.add(labelIcon, new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 1, 1));
        itemPanel.add(labelNum, new GridBagConstraints(1, 0, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.CENTER, new Insets(0, 0, 0, 0), 1, 1));
        itemPanel.updateUI();
        itemPanel.setPreferredSize(new Dimension(180, 25));


    }

    //将项面板设置为选择状态
    public void setSelectPanel(JPanel panel, QQComItem item) {
        JPanel itemPanel = panel;
        //调用图片缩放方法创建头像标签
        JLabel labelIcon = new JLabel(getResizePicture((ImageIcon) item.getIcon(), maxIconDim));
        JLabel labelName = new JLabel(item.getName());      //昵称标签
        JLabel labelNum = new JLabel(item.getNum());    //号码标签
        //网格布局用于存放昵称和号码
        //JPanel interPanel = new JPanel(new GridLayout(2, 1));

        itemPanel.removeAll();
        itemPanel.setLayout(new GridBagLayout());

        //设置空白边框 上左右下
//        labelIcon.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
        //labelName.setBorder(BorderFactory.createEmptyBorder(2, 5, 2, 2));
        //labelNum.setBorder(BorderFactory.createEmptyBorder(2, 5, 2, 2));

        //设置字体
        labelName.setFont(selectNameFont);
        labelNum.setFont(selectNumFont);
        //前景色 
        labelName.setForeground(selectNameForeColor);
        labelNum.setForeground(selectNumForeColor);
        labelX.setForeground(Color.WHITE);

        //背景色
        labelName.setBackground(selectBackColor);
        labelNum.setBackground(selectBackColor);
        labelX.setBackground(selectBackColor);
//        interPanel.setBackground(selectBackColor);
        itemPanel.setBackground(selectBackColor);

        //将组件添加到合适位置
  //      interPanel.add(labelName);
    //    interPanel.add(labelNum);
        //GridBagLayout用法 下面x,y为x轴 y轴
        //组件 new GridBagConstraints(位置x,y, 组件单元格数x,y, 分布额外空间处理x,y,组件小于区域处理x,y, 组件大于区域x,y, 分配权限x,y)        
//        itemPanel.add(labelIcon, new GridBagConstraints(0, 0, 1, 1, 0, 1, GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 1, 1));
        itemPanel.add(labelIcon, new GridBagConstraints(0, 0, 1, 2, 0, 1, GridBagConstraints.WEST, GridBagConstraints.CENTER, new Insets(2, 2, 2, 2), 0, 0));
        itemPanel.add(labelName, new GridBagConstraints(1, 0, 1, 1, 1, 0, GridBagConstraints.BASELINE_LEADING, GridBagConstraints.CENTER, new Insets(3, 2, 1, 0), 1, 0));
        itemPanel.add(labelNum, new GridBagConstraints(1, 1, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.CENTER, new Insets(1, 2, 3, 0), 1, 0));
        itemPanel.add(labelX, new GridBagConstraints(2, 0, 1, 2, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.CENTER, new Insets(0, 0, 0, 10), 0, 0));
//        itemPanel.add(interPanel, new GridBagConstraints(1, 0, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.CENTER, new Insets(0, 0, 0, 0), 1, 1));
//        itemPanel.add(labelX, new GridBagConstraints(2, 0, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.CENTER, new Insets(5, 5, 5, 10), 0, 0));

        itemPanel.updateUI();
        itemPanel.setPreferredSize(new Dimension(180, 45));
    }

    //选择项监听
    class MyItemListener extends MouseAdapter {

        private QQComItem item;
        private JPanel itemPanel;
        private JLabel labelX;

        public MyItemListener(QQComItem item, JPanel itemPanel, JLabel labelX) {
            this.item = item;
            this.itemPanel = itemPanel;
            this.labelX = labelX;
        }

        @Override
        public void mouseEntered(MouseEvent e) {
            //先将上次选择项的面板设置为未选择状态面板，再设置选择项为选择状态面板
            DefaultComboBoxModel comboBoxModel = (DefaultComboBoxModel) comboBox.getModel();
            QQComItem selectItem = (QQComItem) comboBoxModel.getSelectedItem();
            JComponent com = values.get(selectItem);
            if (com != null && com instanceof JPanel) {
                setItemPanel((JPanel) com, selectItem);
            }
            setSelectPanel((JPanel) e.getComponent(), item);
        }

        @Override
        public void mouseExited(MouseEvent e) {
            //setItemPanel((JPanel)e.getComponent(),item);
            setItemPanel(itemPanel, item);
        }

        //对标签labelX直接加标签会出现一些问题，加在面板上却不会
        @Override
        public void mouseClicked(MouseEvent e) {
            if (!SwingUtilities.isLeftMouseButton(e)) {
                return;
            }
            DefaultComboBoxModel comboBoxModel = (DefaultComboBoxModel) comboBox.getModel();
            if (isDel(e.getPoint(), labelX)) {
                //调用MComboBox中fireItemDeleting实现接口中方法
                if (MComboBox.fireItemDeleting(item)) {
                    comboBoxModel.removeElement(item);
                    //调用MComboBox中fireItemDeleted实现接口中方法
                    MComboBox.fireItemDeleted(item);
                    listPanel.remove(itemPanel);
                }
            } else {
                comboBoxModel.setSelectedItem(item);
                //调用MComboBox中fireItemSelected实现接口中方法
                MComboBox.fireItemSelected(item);
                setItemPanel(itemPanel, item);
            }
            QQComboBoxPopup.this.hide();
            listPanel.updateUI();
        }

        @Override
        public void mouseMoved(MouseEvent e) {
            if (isDel(e.getPoint(), labelX)) {
                labelX.setBorder(BorderFactory.createLineBorder(new Color(167, 195, 212)));
            } else {
                labelX.setBorder(null);
            }
        }
    }

    //判断鼠标是否在labelX上
    private boolean isDel(Point mousePoint, JLabel labelX) {
        return labelX.getBounds().contains(mousePoint);
        //return mousePoint.x > labelX.getX() && mousePoint.x < (labelX.getX() + labelX.getWidth()) && mousePoint.y > labelX.getY() && mousePoint.y < labelX.getY() + labelX.getHeight();
    }

    //实现ComboBox编辑框中内容在弹出菜单中选择
    //通知 PopupMenuListener 此弹出菜单将变得可见。
    @Override
    protected void firePopupMenuWillBecomeVisible() {
        DefaultComboBoxModel comboBoxModel = (DefaultComboBoxModel) comboBox.getModel();
        QQComItem selectItem = (QQComItem) comboBoxModel.getSelectedItem();
        JComponent com = values.get(selectItem);
        //设置编辑中内容在打开Popup菜单时为选中状态面板
        //如果选择项的映射值即其选择面板不为空且属于JPanel
        if (com != null && com instanceof JPanel) {
            setSelectPanel((JPanel) com, selectItem);
        }
        super.firePopupMenuWillBecomeVisible();
    }

    //图片缩放
    public static ImageIcon getResizePicture(ImageIcon originalPic, Dimension changedImageDim) {
        if (originalPic == null || changedImageDim == null) {
            return originalPic;
        }
        int changedImageWidth = changedImageDim.width;
        int changedImageHeight = changedImageDim.height;

        // 获得原始图片的宽度。
        int originalImageWidth = originalPic.getIconWidth();
        // 获得原始图片的高度。
        int originalImageHeight = originalPic.getIconHeight();
        if (originalImageWidth <= 0 || originalImageHeight <= 0) {
            return originalPic;
        }
        BufferedImage oriImage = new BufferedImage(originalImageWidth, originalImageHeight, BufferedImage.TYPE_3BYTE_BGR);
        //        oriImage.createGraphics().drawImage(originalPic.getImage(), 0, 0, null);
        //将透明替换为白色
        Graphics2D g = oriImage.createGraphics();
        g.setColor(Color.white);
        g.fillRect(0, 0, originalImageWidth, originalImageHeight);
        g.drawImage(originalPic.getImage(), 0, 0, null);

        // 生成处理后的图片存储空间。
        BufferedImage changedImage = new BufferedImage(changedImageWidth, changedImageHeight, BufferedImage.TYPE_3BYTE_BGR);

        double widthBo = (double) changedImageWidth / originalImageWidth;
        double heightBo = (double) changedImageHeight / originalImageHeight;

        AffineTransform transform = new AffineTransform();
        transform.setToScale(widthBo, heightBo);

        // 根据原始图片生成处理后的图片。
        AffineTransformOp ato = new AffineTransformOp(transform, null);
        ato.filter(oriImage, changedImage);
        // 返回处理后的图片
        return new ImageIcon(changedImage);
    }
}